<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是kernel——open源码解析的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV05-03-Kernel-05-03-02-open函数解析1">
<meta property="og:url" content="https://sumumm.github.io/post/9cc69d79.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是kernel——open源码解析的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214153842041.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214155242924.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214214800378.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214223720583.png">
<meta property="article:published_time" content="2024-12-17T15:25:18.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:57.045Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV05-系统镜像">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214153842041.png">


<link rel="canonical" href="https://sumumm.github.io/post/9cc69d79.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":"","permalink":"https://sumumm.github.io/post/9cc69d79.html","path":"post/9cc69d79.html","title":"LV05-03-Kernel-05-03-02-open函数解析1"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV05-03-Kernel-05-03-02-open函数解析1 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B"><span class="nav-text">一、一个实例</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E6%B5%8B%E8%AF%95demo"><span class="nav-text">1. 测试demo</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%EF%BC%9F"><span class="nav-text">2. 系统调用？</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81open%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="nav-text">二、open源码分析</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8openat"><span class="nav-text">1. 系统调用openat()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-do-sys-open"><span class="nav-text">2. do_sys_open()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-build-open-flags"><span class="nav-text">2.1 build_open_flags()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-get-unused-fd-flags"><span class="nav-text">2.2 get_unused_fd_flags()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-do-filp-open"><span class="nav-text">3. do_filp_open()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-path-openat"><span class="nav-text">4. path_openat()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-path-init"><span class="nav-text">4.1 path_init()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-1-set-root"><span class="nav-text">4.1.1 set_root()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-2-nd-jump-root"><span class="nav-text">4.1.2 nd_jump_root()</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-link-path-walk"><span class="nav-text">4.2 link_path_walk()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-1-walk-component"><span class="nav-text">4.2.1 walk_component()</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-%E6%80%BB%E7%BB%93"><span class="nav-text">4.3 总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-do-last"><span class="nav-text">5. do_last()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-1-complete-walk"><span class="nav-text">5.1 complete_walk()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-legitimize-links"><span class="nav-text">5.1.1 legitimize_links()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-2-legitimize-path"><span class="nav-text">5.1.2 legitimize_path()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-3-%E6%80%BB%E7%BB%93"><span class="nav-text">5.1.3 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-audit-inode"><span class="nav-text">5.2 audit_inode()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-may-open"><span class="nav-text">5.3 may_open()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-4-%E6%80%BB%E7%BB%93"><span class="nav-text">5.4 总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-vfs-open"><span class="nav-text">6. vfs_open()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-do-dentry-open"><span class="nav-text">6.1 do_dentry_open()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-%E5%90%84%E4%B8%AA%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E"><span class="nav-text">7. 各个函数返回</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#8-%E6%80%BB%E7%BB%93"><span class="nav-text">8. 总结</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/9cc69d79.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV05-03-Kernel-05-03-02-open函数解析1 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV05-03-Kernel-05-03-02-open函数解析1
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2024-12-17 23:25:18" itemprop="dateCreated datePublished" datetime="2024-12-17T23:25:18+08:00">2024-12-17</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/" itemprop="url" rel="index"><span itemprop="name">02IMX6ULL平台</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/" itemprop="url" rel="index"><span itemprop="name">LV05-系统镜像</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>7.1k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>26 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是kernel——open源码解析的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" rowspan="5">PC端开发环境</td>        <td align="center" width=150px>Windows</td>        <td align="left">Windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu20.04.2的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 17 Pro</td>        <td align="left">17.6.0 build-24238078</td>      </tr>    <tr>        <td align="center">终端软件</td>        <td align="left">MobaXterm(Professional Edition v23.0 Build 5042 (license))</td>    </tr>    <tr>        <td align="center">Win32DiskImager</td>        <td align="left">Win32DiskImager v1.0</td>      </tr>    <tr>        <td align="center" rowspan="3">Linux开发板环境</td>        <td align="center">Linux开发板</td>        <td align="left">正点原子 i.MX6ULL Linux 阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，使用的uboot版本为U-Boot 2019.04</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.19.71(NXP官方提供)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="5">官方网站</td>        <td align="left"><a href="https://www.arm.com/" target="_blank">https://www.arm.com/</a></td>        <td align="left">ARM官方网站，在这里我们可以找到Cotex-Mx以及ARMVx的一些文档</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/" target="_blank">https://www.nxp.com.cn/ </a></td>        <td align="left">NXP官方网站</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxpic.org.cn/" target="_blank">https://www.nxpic.org.cn/</a></td><td align="left">NXP 官方社区</td>    </tr>    <tr>        <td align="left"><a href="https://u-boot.readthedocs.io/en/latest/" target="_blank">https://u-boot.readthedocs.io/en/latest/</a></td><td align="left">u-boot官网</td>    </tr>    <tr>        <td align="left"><a href="https://www.kernel.org/" target="_blank">https://www.kernel.org/</a></td><td align="left">linux内核官网</td>    </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="3">NXP</td>        <td align="left"><a href="https://github.com/nxp-imx" target="_blank">https://github.com/nxp-imx</a></td>        <td align="left">NXP imx开发资源GitHub组织，里边会有u-boot和linux内核的仓库</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/linux-imx/releases/tag/v4.19.71" target="_blank">nxp-imx/linux-imx/releases/tag/v4.19.71</a></td>        <td align="left">NXP linux内核仓库tags中的v4.19.71</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0" target="_blank">nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0</a></td>        <td align="left">NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0</td>    </tr>    <tr>        <td align="center" rowspan="2">I.MX6ULL</td>        <td align="left"><a href="https://www.nxp.com.cn/docs/en/data-sheet/IMX6ULLIEC.pdf" target="_blank">i.MX 6ULL Applications Processors for Industrial Products</a></td>        <td align="left">I.MX6ULL 芯片手册（datasheet，可以在线查看）</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/webapp/Download?colCode=IMX6ULLRM&lang_cd=zh" target="_blank">i.MX 6ULL Applications ProcessorReference Manual</a></td>        <td align="left">I.MX6ULL 参考手册（下载后才能查看，需要登录NXP官网）</td>    </tr>    <tr>        <td align="center" rowspan="2">Source Code</td>        <td align="left"><a href="https://elixir.bootlin.com/linux/latest/source" target="_blank">https://elixir.bootlin.com/linux/latest/source</a></td>        <td align="left">linux kernel源码</td>    </tr>    <tr>        <td align="left"><a href="https://elixir.bootlin.com/u-boot/latest/source" target="_blank">https://elixir.bootlin.com/u-boot/latest/source</a></td>        <td align="left">uboot源码</td>    </tr></table>
              </div>
            </details>

<h1 id="一、一个实例"><a href="#一、一个实例" class="headerlink" title="一、一个实例"></a><font size=3>一、一个实例</font></h1><h2 id="1-测试demo"><a href="#1-测试demo" class="headerlink" title="1. 测试demo"></a><font size=3>1. 测试demo</font></h2><p>这里还是先以打开一个文本文件为例：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> fd = open(<span class="string">&quot;/home/sumu/7Linux/test.txt&quot;</span>, O_CREAT | O_RDWR);</span><br><span class="line">    close(fd);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-系统调用？"><a href="#2-系统调用？" class="headerlink" title="2. 系统调用？"></a><font size=3>2. 系统调用？</font></h2><p>open用的哪个系统调用？其实前面已经了解过了，这里在回顾一下吧，以这个demo为例：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> fd = open(<span class="string">&quot;/home/sumu/7Linux/test.txt&quot;</span>, O_RDONLY);</span><br><span class="line">    close(fd);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>使用strace命令看一下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gcc main.c -Wall</span><br><span class="line">touch test.txt</span><br><span class="line">strace -o syscall ./a.out</span><br></pre></td></tr></table></figure>

<p>会发现有这么一行：</p>
<figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openat(AT_FDCWD, &quot;/home/sumu/7Linux/test.txt&quot;, O_RDONLY)  = 3</span><br></pre></td></tr></table></figure>

<p>从这里可以看出，调用的是openat这个系统调用。</p>
<h1 id="二、open源码分析"><a href="#二、open源码分析" class="headerlink" title="二、open源码分析"></a><font size=3>二、open源码分析</font></h1><h2 id="1-系统调用openat"><a href="#1-系统调用openat" class="headerlink" title="1. 系统调用openat()"></a><font size=3>1. 系统调用openat()</font></h2><p>我们前面一节已经找到了open的系统调用openat，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L1109">open.c - fs&#x2F;open.c - <em>openat</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">SYSCALL_DEFINE4(openat, <span class="type">int</span>, dfd, <span class="type">const</span> <span class="type">char</span> __user *, filename, <span class="type">int</span>, flags,</span><br><span class="line">		<span class="type">umode_t</span>, mode)</span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (force_o_largefile())</span><br><span class="line">		flags |= O_LARGEFILE;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> do_sys_open(dfd, filename, flags, mode);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>有些版本的系统调用可能直接就是open，这个搜一下就会知道了。其实不管是open还是openat，都会调用do_sys_open()函数进行处理。根据前面的实例，这里的参数应该是这样的：</p>
<figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openat(AT_FDCWD, &quot;/home/sumu/7Linux/test.txt&quot;, O_RDONLY) = 3</span><br></pre></td></tr></table></figure>

<p>这里的AT_FDCWD定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/uapi/linux/fcntl.h#L78">fcntl.h - include&#x2F;uapi&#x2F;linux&#x2F;fcntl.h - <em>AT_FDCWD</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> AT_FDCWD		-100    <span class="comment">/* Special value used to indicate openat should use the curren working directory. */</span></span></span><br></pre></td></tr></table></figure>

<p>这个force_o_largefile()函数应该是定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/fcntl.h#L15">fcntl.h - include&#x2F;linux&#x2F;fcntl.h - <em>force_o_largefile</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> force_o_largefile</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> force_o_largefile() (BITS_PER_LONG != 32)</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure>

<p>最后调用do_sys_open的时候参数应该是这样对应的：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * dfd = -100 (AT_FDCWD)</span></span><br><span class="line"><span class="comment"> * filename = &quot;/home/sumu/7Linux/test.txt&quot;</span></span><br><span class="line"><span class="comment"> * flags = O_RDONLY | O_LARGEFILE;</span></span><br><span class="line"><span class="comment"> * mode = 0</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>

<h2 id="2-do-sys-open"><a href="#2-do-sys-open" class="headerlink" title="2. do_sys_open()"></a><font size=3>2. do_sys_open()</font></h2><p>do_sys_open()函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L1073">open.c - fs&#x2F;open.c - <em>do_sys_open</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">long</span> <span class="title function_">do_sys_open</span><span class="params">(<span class="type">int</span> dfd, <span class="type">const</span> <span class="type">char</span> __user *filename, <span class="type">int</span> flags, <span class="type">umode_t</span> mode)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">open_flags</span> <span class="title">op</span>;</span></span><br><span class="line">	<span class="type">int</span> fd = build_open_flags(flags, mode, &amp;op);</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">filename</span> *<span class="title">tmp</span>;</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (fd)</span><br><span class="line">		<span class="keyword">return</span> fd;</span><br><span class="line"></span><br><span class="line">	tmp = getname(filename);</span><br><span class="line">	<span class="keyword">if</span> (IS_ERR(tmp))</span><br><span class="line">		<span class="keyword">return</span> PTR_ERR(tmp);</span><br><span class="line"></span><br><span class="line">	fd = get_unused_fd_flags(flags);</span><br><span class="line">	<span class="keyword">if</span> (fd &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">		<span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">f</span> =</span> do_filp_open(dfd, tmp, &amp;op);</span><br><span class="line">		<span class="keyword">if</span> (IS_ERR(f)) &#123;</span><br><span class="line">			put_unused_fd(fd);</span><br><span class="line">			fd = PTR_ERR(f);</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			fsnotify_open(f);</span><br><span class="line">			fd_install(fd, f);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	putname(tmp);</span><br><span class="line">	<span class="keyword">return</span> fd;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第 14 行：获取一个该进程未使用的fd；</p>
<p>第 16 行：生成一个struct file，生成这个对象的时候通过do_filp_open()函数进行。</p>
<p>第 22 行：将fd与struct file进行绑定。</p>
<h3 id="2-1-build-open-flags"><a href="#2-1-build-open-flags" class="headerlink" title="2.1 build_open_flags()"></a><font size=3>2.1 build_open_flags()</font></h3><p>build_open_flags()定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L949">open.c - fs&#x2F;open.c - <em>build_open_flags</em></a>，这个函数主要是用来构建flags，并返回到结构体 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/internal.h#L109">struct open_flags</a> op中。该函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">build_open_flags</span><span class="params">(<span class="type">int</span> flags, <span class="type">umode_t</span> mode, <span class="keyword">struct</span> open_flags *op)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> lookup_flags = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> acc_mode = ACC_MODE(flags);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	 * Clear out all open flags we don&#x27;t know about so that we don&#x27;t report</span></span><br><span class="line"><span class="comment">	 * them in fcntl(F_GETFD) or similar interfaces.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	flags &amp;= VALID_OPEN_FLAGS;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; (O_CREAT | __O_TMPFILE)) <span class="comment">// if 判断为 0 </span></span><br><span class="line">		op-&gt;mode = (mode &amp; S_IALLUGO) | S_IFREG;</span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">		op-&gt;mode = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* Must never be set by userspace */</span></span><br><span class="line">	flags &amp;= ~FMODE_NONOTIFY &amp; ~O_CLOEXEC;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only</span></span><br><span class="line"><span class="comment">	 * check for O_DSYNC if the need any syncing at all we enforce it&#x27;s</span></span><br><span class="line"><span class="comment">	 * always set instead of having to deal with possibly weird behaviour</span></span><br><span class="line"><span class="comment">	 * for malicious applications setting only __O_SYNC.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; __O_SYNC) <span class="comment">// if 判断为 0 </span></span><br><span class="line">		flags |= O_DSYNC;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; __O_TMPFILE) &#123; <span class="comment">// if 判断为 0 </span></span><br><span class="line">		<span class="keyword">if</span> ((flags &amp; O_TMPFILE_MASK) != O_TMPFILE)</span><br><span class="line">			<span class="keyword">return</span> -EINVAL;</span><br><span class="line">		<span class="keyword">if</span> (!(acc_mode &amp; MAY_WRITE))</span><br><span class="line">			<span class="keyword">return</span> -EINVAL;</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (flags &amp; O_PATH) &#123;</span><br><span class="line">		<span class="comment">/*</span></span><br><span class="line"><span class="comment">		 * If we have O_PATH in the open flag. Then we</span></span><br><span class="line"><span class="comment">		 * cannot have anything other than the below set of flags</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">		flags &amp;= O_DIRECTORY | O_NOFOLLOW | O_PATH;</span><br><span class="line">		acc_mode = <span class="number">0</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	op-&gt;open_flag = flags;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* O_TRUNC implies we need access checks for write permissions */</span></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; O_TRUNC) <span class="comment">// if 判断为 0 </span></span><br><span class="line">		acc_mode |= MAY_WRITE;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* Allow the LSM permission hook to distinguish append</span></span><br><span class="line"><span class="comment">	   access from general write access. */</span></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; O_APPEND) <span class="comment">// if 判断为 0 </span></span><br><span class="line">		acc_mode |= MAY_APPEND;</span><br><span class="line"></span><br><span class="line">	op-&gt;acc_mode = acc_mode;</span><br><span class="line"></span><br><span class="line">	op-&gt;intent = flags &amp; O_PATH ? <span class="number">0</span> : LOOKUP_OPEN;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; O_CREAT) &#123; <span class="comment">// if 判断为 0 </span></span><br><span class="line">		op-&gt;intent |= LOOKUP_CREATE;</span><br><span class="line">		<span class="keyword">if</span> (flags &amp; O_EXCL)</span><br><span class="line">			op-&gt;intent |= LOOKUP_EXCL;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (flags &amp; O_DIRECTORY) <span class="comment">// if 判断为 0 </span></span><br><span class="line">		lookup_flags |= LOOKUP_DIRECTORY;</span><br><span class="line">	<span class="keyword">if</span> (!(flags &amp; O_NOFOLLOW)) <span class="comment">// if 判断为 1</span></span><br><span class="line">		lookup_flags |= LOOKUP_FOLLOW;</span><br><span class="line">	op-&gt;lookup_flags = lookup_flags;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>最终，op各个成员的值如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">op-&gt;mode = <span class="number">0</span></span><br><span class="line">op-&gt;open_flag = <span class="number">0x8000</span></span><br><span class="line">op-&gt;acc_mode = <span class="number">0x4</span></span><br><span class="line">op-&gt;intent = <span class="number">0x100</span> (LOOKUP_OPEN)</span><br><span class="line">op-&gt;lookup_flags = <span class="number">0x1</span> (LOOKUP_FOLLOW)</span><br></pre></td></tr></table></figure>

<p>这里分析的时候，不考虑很多特殊情况，该 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L949">build_open_flags()</a>函数中很多代码是不用执行的。</p>
<h3 id="2-2-get-unused-fd-flags"><a href="#2-2-get-unused-fd-flags" class="headerlink" title="2.2 get_unused_fd_flags()"></a><font size=3>2.2 get_unused_fd_flags()</font></h3><p>在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/file.c#L543">get_unused_fd_flags()</a> 函数中，找到一个可用的文件描述符，并返回该值，这里更深入一层就会涉及到文件描述符的分配以及查找，相关的函数和结构可以看这里《01嵌入式开发&#x2F;02IMX6ULL平台&#x2F;LV05-系统镜像&#x2F;LV05-03-Kernel-05-02-文件描述符分配.md》。这个函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_unused_fd_flags</span><span class="params">(<span class="type">unsigned</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">return</span> __alloc_fd(current-&gt;files, <span class="number">0</span>, rlimit(RLIMIT_NOFILE), flags);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(get_unused_fd_flags);</span><br></pre></td></tr></table></figure>

<p>可见它最后是调用了__alloc_fd()函数。</p>
<h2 id="3-do-filp-open"><a href="#3-do-filp-open" class="headerlink" title="3. do_filp_open()"></a><font size=3>3. do_filp_open()</font></h2><p>do_filp_open()函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3556">namei.c - fs&#x2F;namei.c - <em>do_filp_open</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> file *<span class="title function_">do_filp_open</span><span class="params">(<span class="type">int</span> dfd, <span class="keyword">struct</span> filename *pathname,</span></span><br><span class="line"><span class="params">		<span class="type">const</span> <span class="keyword">struct</span> open_flags *op)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nameidata</span> <span class="title">nd</span>;</span></span><br><span class="line">	<span class="type">int</span> flags = op-&gt;lookup_flags;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span>;</span></span><br><span class="line"></span><br><span class="line">	set_nameidata(&amp;nd, dfd, pathname);</span><br><span class="line">	filp = path_openat(&amp;nd, op, flags | LOOKUP_RCU);</span><br><span class="line">	<span class="keyword">if</span> (unlikely(filp == ERR_PTR(-ECHILD)))</span><br><span class="line">		filp = path_openat(&amp;nd, op, flags);</span><br><span class="line">	<span class="keyword">if</span> (unlikely(filp == ERR_PTR(-ESTALE)))</span><br><span class="line">		filp = path_openat(&amp;nd, op, flags | LOOKUP_REVAL);</span><br><span class="line">	restore_nameidata();</span><br><span class="line">	<span class="keyword">return</span> filp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第 8 行：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L513">set_nameidata()</a>函数主要用来设置结构体 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L490">struct nameidata</a> 的值，这个结构体是个非常重要的结构体，在解析和查找路径名时会经常引用到。函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">set_nameidata</span><span class="params">(<span class="keyword">struct</span> nameidata *p, <span class="type">int</span> dfd, <span class="keyword">struct</span> filename *name)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nameidata</span> *<span class="title">old</span> =</span> current-&gt;nameidata;</span><br><span class="line">	p-&gt;<span class="built_in">stack</span> = p-&gt;internal;</span><br><span class="line">	p-&gt;dfd = dfd;</span><br><span class="line">	p-&gt;name = name;</span><br><span class="line">	p-&gt;total_link_count = old ? old-&gt;total_link_count : <span class="number">0</span>;</span><br><span class="line">	p-&gt;saved = old;</span><br><span class="line">	current-&gt;nameidata = p;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第 13 行：这个函数其实后面调用的是path_openat()，后面我们继续分析。</p>
<h2 id="4-path-openat"><a href="#4-path-openat" class="headerlink" title="4. path_openat()"></a><font size=3>4. path_openat()</font></h2><p>path_openat()函数入口参数如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 函数入口参数： flags = LOOKUP_FOLLOW | LOOKUP_RCU */</span></span><br></pre></td></tr></table></figure>

<p>函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">namei.c - fs&#x2F;namei.c - <em>path_openat</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">struct</span> file *<span class="title function_">path_openat</span><span class="params">(<span class="keyword">struct</span> nameidata *nd,</span></span><br><span class="line"><span class="params">			<span class="type">const</span> <span class="keyword">struct</span> open_flags *op, <span class="type">unsigned</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">file</span>;</span></span><br><span class="line">	<span class="type">int</span> error;</span><br><span class="line"></span><br><span class="line">	file = alloc_empty_file(op-&gt;open_flag, current_cred());</span><br><span class="line">	<span class="keyword">if</span> (IS_ERR(file))</span><br><span class="line">		<span class="keyword">return</span> file;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (unlikely(file-&gt;f_flags &amp; __O_TMPFILE)) &#123;</span><br><span class="line">		error = do_tmpfile(nd, flags, op, file);</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (unlikely(file-&gt;f_flags &amp; O_PATH)) &#123;</span><br><span class="line">		error = do_o_path(nd, flags, file);</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="type">const</span> <span class="type">char</span> *s = path_init(nd, flags);</span><br><span class="line">		<span class="keyword">while</span> (!(error = link_path_walk(s, nd)) &amp;&amp;</span><br><span class="line">			(error = do_last(nd, file, op)) &gt; <span class="number">0</span>) &#123;</span><br><span class="line">			nd-&gt;flags &amp;= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);</span><br><span class="line">			s = trailing_symlink(nd);</span><br><span class="line">		&#125;</span><br><span class="line">		terminate_walk(nd);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (likely(!error)) &#123;</span><br><span class="line">		<span class="keyword">if</span> (likely(file-&gt;f_mode &amp; FMODE_OPENED))</span><br><span class="line">			<span class="keyword">return</span> file;</span><br><span class="line">		WARN_ON(<span class="number">1</span>);</span><br><span class="line">		error = -EINVAL;</span><br><span class="line">	&#125;</span><br><span class="line">	fput(file);</span><br><span class="line">	<span class="keyword">if</span> (error == -EOPENSTALE) &#123;</span><br><span class="line">		<span class="keyword">if</span> (flags &amp; LOOKUP_RCU)</span><br><span class="line">			error = -ECHILD;</span><br><span class="line">		<span class="keyword">else</span></span><br><span class="line">			error = -ESTALE;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> ERR_PTR(error);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第 7 行：path_openat()该函数通过<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/file_table.c#L133">alloc_empty_file()</a>为该进程生成了一个struct file。</p>
<p>第 16 行：path_init()函数用于初始化 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L490">struct nameidata</a> 结构体。</p>
<p>第 18 行：最后由do_last()函数完成剩下的打开步骤。</p>
<h3 id="4-1-path-init"><a href="#4-1-path-init" class="headerlink" title="4.1 path_init()"></a><font size=3>4.1 path_init()</font></h3><p>先看其中的 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2172">path_init()</a> 函数。在解析路径的过程中，需要遍历路径中的每个部分，而其中使用结构体 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L490">struct nameidata</a> 来保存当前遍历的状态。<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2172">path_init()</a>函数主要用来将该结构体初始化。函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* must be paired with terminate_walk() */</span></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">char</span> *<span class="title function_">path_init</span><span class="params">(<span class="keyword">struct</span> nameidata *nd, <span class="type">unsigned</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* 函数入口参数： flags = LOOKUP_FOLLOW | LOOKUP_RCU */</span></span><br><span class="line">	<span class="type">const</span> <span class="type">char</span> *s = nd-&gt;name-&gt;name; <span class="comment">/* s = &quot;/home/sumu/7Linux/test.txt&quot; */</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!*s) <span class="comment">//if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line"></span><br><span class="line">	nd-&gt;last_type = LAST_ROOT; <span class="comment">/* if there are only slashes... */</span></span><br><span class="line">	nd-&gt;flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;</span><br><span class="line">	nd-&gt;depth = <span class="number">0</span>;</span><br><span class="line">	<span class="keyword">if</span> (flags &amp; LOOKUP_ROOT) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	nd-&gt;root.mnt = <span class="literal">NULL</span>;</span><br><span class="line">	nd-&gt;path.mnt = <span class="literal">NULL</span>;</span><br><span class="line">	nd-&gt;path.dentry = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">	nd-&gt;m_seq = read_seqbegin(&amp;mount_lock);</span><br><span class="line">	<span class="keyword">if</span> (*s == <span class="string">&#x27;/&#x27;</span>) &#123; <span class="comment">// if 判断为 1, 表示从绝对路径&#x27;/&#x27;开始解析目录</span></span><br><span class="line">		set_root(nd);</span><br><span class="line">		<span class="keyword">if</span> (likely(!nd_jump_root(nd)))</span><br><span class="line">			<span class="keyword">return</span> s; <span class="comment">// 函数由此处返回</span></span><br><span class="line">		<span class="keyword">return</span> ERR_PTR(-ECHILD);</span><br><span class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (nd-&gt;dfd == AT_FDCWD) &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="4-1-1-set-root"><a href="#4-1-1-set-root" class="headerlink" title="4.1.1 set_root()"></a><font size=3>4.1.1 set_root()</font></h4><p>下面分析一下 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L810">set_root()</a> 函数，该函数设置struct nameidata nd 的值，使得路径解析从根目录开始（而不是当前工作目录）。函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">set_root</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">fs_struct</span> *<span class="title">fs</span> =</span> current-&gt;fs;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;flags &amp; LOOKUP_RCU) &#123;</span><br><span class="line">		<span class="type">unsigned</span> seq;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">do</span> &#123;</span><br><span class="line">			seq = read_seqcount_begin(&amp;fs-&gt;seq);</span><br><span class="line">			nd-&gt;root = fs-&gt;root;</span><br><span class="line">			nd-&gt;root_seq = __read_seqcount_begin(&amp;nd-&gt;root.dentry-&gt;d_seq);</span><br><span class="line">		&#125; <span class="keyword">while</span> (read_seqcount_retry(&amp;fs-&gt;seq, seq));</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		get_fs_root(fs, &amp;nd-&gt;root);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="4-1-2-nd-jump-root"><a href="#4-1-2-nd-jump-root" class="headerlink" title="4.1.2 nd_jump_root()"></a><font size=3>4.1.2 nd_jump_root()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L846">nd_jump_root()</a>函数的作用和 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L810">set_root()</a> 函数差不多，但做的工作要更多一些。函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">nd_jump_root</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;flags &amp; LOOKUP_RCU) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">d</span>;</span></span><br><span class="line">		nd-&gt;path = nd-&gt;root;</span><br><span class="line">		d = nd-&gt;path.dentry;</span><br><span class="line">		nd-&gt;inode = d-&gt;d_inode;</span><br><span class="line">		nd-&gt;seq = nd-&gt;root_seq;</span><br><span class="line">		<span class="keyword">if</span> (unlikely(read_seqcount_retry(&amp;d-&gt;d_seq, nd-&gt;seq))) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> -ECHILD;</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		path_put(&amp;nd-&gt;path);</span><br><span class="line">		nd-&gt;path = nd-&gt;root;</span><br><span class="line">		path_get(&amp;nd-&gt;path);</span><br><span class="line">		nd-&gt;inode = nd-&gt;path.dentry-&gt;d_inode;</span><br><span class="line">	&#125;</span><br><span class="line">	nd-&gt;flags |= LOOKUP_JUMPED;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="4-2-link-path-walk"><a href="#4-2-link-path-walk" class="headerlink" title="4.2 link_path_walk()"></a><font size=3>4.2 link_path_walk()</font></h3><p>上面对struct nameidata nd 结构体初始化完成之后，便进入路径解析的主要部分： <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2068">link_path_walk()</a> 函数。在这个函数里面，将路径名逐步解析，并最终找到目标文件的 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/dcache.h#L88">struct dentry</a> 结构体（保存在参数 struct nameidata *nd 中）。该函数很长，在这里，由于我们并不涉及链接文件以及特殊文件名（.和..)的解析问题，该函数可简化如下（忽略权限检查及错误处理）：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Name resolution.</span></span><br><span class="line"><span class="comment"> * This is the basic name resolution function, turning a pathname into</span></span><br><span class="line"><span class="comment"> * the final dentry. We expect &#x27;base&#x27; to be positive and a directory.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 and nd will have valid dentry and mnt on success.</span></span><br><span class="line"><span class="comment"> * Returns error and drops reference to input namei data on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">link_path_walk</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name, <span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (IS_ERR(name))</span><br><span class="line">		<span class="keyword">return</span> PTR_ERR(name);</span><br><span class="line">	<span class="keyword">while</span> (*name==<span class="string">&#x27;/&#x27;</span>)</span><br><span class="line">		name++;</span><br><span class="line">	<span class="keyword">if</span> (!*name) <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* At this point we know we have a real path component. */</span></span><br><span class="line">	<span class="keyword">for</span>(;;) &#123;</span><br><span class="line">		u64 hash_len;</span><br><span class="line">		<span class="type">int</span> type;</span><br><span class="line"></span><br><span class="line">		err = may_lookup(nd);</span><br><span class="line">		<span class="keyword">if</span> (err) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> err;</span><br><span class="line"></span><br><span class="line">		hash_len = hash_name(nd-&gt;path.dentry, name);</span><br><span class="line"></span><br><span class="line">		type = LAST_NORM;</span><br><span class="line">		<span class="keyword">if</span> (name[<span class="number">0</span>] == <span class="string">&#x27;.&#x27;</span>) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="comment">// ......</span></span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (likely(type == LAST_NORM)) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">			<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">parent</span> =</span> nd-&gt;path.dentry;</span><br><span class="line">			nd-&gt;flags &amp;= ~LOOKUP_JUMPED;</span><br><span class="line">			<span class="keyword">if</span> (unlikely(parent-&gt;d_flags &amp; DCACHE_OP_HASH)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">				<span class="comment">// ......</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		nd-&gt;last.hash_len = hash_len;</span><br><span class="line">		nd-&gt;last.name = name;</span><br><span class="line">		nd-&gt;last_type = type;</span><br><span class="line"></span><br><span class="line">		name += hashlen_len(hash_len);</span><br><span class="line">		<span class="keyword">if</span> (!*name) <span class="comment">// 除了路径中的最后一部分（&#x27;test.txt&#x27;）if判断为1，其他 if 判断为 0</span></span><br><span class="line">			<span class="keyword">goto</span> OK;</span><br><span class="line">		<span class="comment">/*</span></span><br><span class="line"><span class="comment">		 * If it wasn&#x27;t NUL, we know it was &#x27;/&#x27;. Skip that</span></span><br><span class="line"><span class="comment">		 * slash, and continue until no more slashes.</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">		<span class="keyword">do</span> &#123;</span><br><span class="line">			name++;</span><br><span class="line">		&#125; <span class="keyword">while</span> (unlikely(*name == <span class="string">&#x27;/&#x27;</span>));</span><br><span class="line">		<span class="keyword">if</span> (unlikely(!*name)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">OK:</span><br><span class="line">			<span class="comment">/* pathname body, done */</span></span><br><span class="line">			<span class="keyword">if</span> (!nd-&gt;depth)</span><br><span class="line">				<span class="keyword">return</span> <span class="number">0</span>; <span class="comment">// 解析到路径最后一部分时，该函数由此处返回</span></span><br><span class="line">			<span class="comment">//......</span></span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="comment">/* not the last component */</span></span><br><span class="line">			err = walk_component(nd, WALK_FOLLOW | WALK_MORE); <span class="comment">// err == 0</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (err &lt; <span class="number">0</span>) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> err;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (err) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="comment">// ......</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span> (unlikely(!d_can_lookup(nd-&gt;path.dentry))) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="comment">//......</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="comment">// go back to for loop</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可见，该函数是在一个死循环for(;;)里面对路径名中的每一个部分进行解析，完成解析后函数返回。解析前几个部分（home 、 sumu 和 7Linux)时，均调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数。</p>
<h4 id="4-2-1-walk-component"><a href="#4-2-1-walk-component" class="headerlink" title="4.2.1 walk_component()"></a><font size=3>4.2.1 walk_component()</font></h4><p> <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数定义如下（以解析‘home’为例来分析该函数）：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">walk_component</span><span class="params">(<span class="keyword">struct</span> nameidata *nd, <span class="type">int</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* 函数入口参数： flags = WALK_FOLLOW | WALK_MORE */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">path</span> <span class="title">path</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">inode</span> *<span class="title">inode</span>;</span></span><br><span class="line">    <span class="type">unsigned</span> seq;</span><br><span class="line">    <span class="type">int</span> err;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * &quot;.&quot; and &quot;..&quot; are special - &quot;..&quot; especially so because it has</span></span><br><span class="line"><span class="comment">     * to be able to know about the current root directory and</span></span><br><span class="line"><span class="comment">     * parent relationships.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (unlikely(nd-&gt;last_type != LAST_NORM)) &#123; <span class="comment">// if 判断为 0 </span></span><br><span class="line">        <span class="comment">//......</span></span><br><span class="line">    &#125;</span><br><span class="line">    err = lookup_fast(nd, &amp;path, &amp;inode, &amp;seq);</span><br><span class="line">    <span class="keyword">if</span> (unlikely(err &lt;= <span class="number">0</span>)) &#123; <span class="comment">// if 判断为 0，这里我们假设相应文件的dentry已经存在于系统缓存中 </span></span><br><span class="line">        <span class="comment">//......</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> step_into(nd, &amp;path, flags, inode, seq);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中我们调用了 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1554">lookup_fast()</a> 函数，仍以解析第一部分”home”为例，此时该函数等价与如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">lookup_fast</span><span class="params">(<span class="keyword">struct</span> nameidata *nd,</span></span><br><span class="line"><span class="params">		       <span class="keyword">struct</span> path *path, <span class="keyword">struct</span> inode **inode,</span></span><br><span class="line"><span class="params">		       <span class="type">unsigned</span> *seqp)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">vfsmount</span> *<span class="title">mnt</span> =</span> nd-&gt;path.mnt;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">dentry</span>, *<span class="title">parent</span> =</span> nd-&gt;path.dentry;</span><br><span class="line">	<span class="type">int</span> status = <span class="number">1</span>;</span><br><span class="line">	<span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	 * Rename seqlock is not required here because in the off chance</span></span><br><span class="line"><span class="comment">	 * of a false negative due to a concurrent rename, the caller is</span></span><br><span class="line"><span class="comment">	 * going to fall back to non-racy lookup.</span></span><br><span class="line"><span class="comment">	 */</span></span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;flags &amp; LOOKUP_RCU) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="type">unsigned</span> seq;</span><br><span class="line">		<span class="type">bool</span> negative;</span><br><span class="line">		dentry = __d_lookup_rcu(parent, &amp;nd-&gt;last, &amp;seq);</span><br><span class="line">		<span class="keyword">if</span> (unlikely(!dentry)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="comment">//......</span></span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="comment">/*</span></span><br><span class="line"><span class="comment">		 * This sequence count validates that the inode matches</span></span><br><span class="line"><span class="comment">		 * the dentry name information from lookup.</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">		*inode = d_backing_inode(dentry);</span><br><span class="line">		negative = d_is_negative(dentry);</span><br><span class="line">		<span class="keyword">if</span> (unlikely(read_seqcount_retry(&amp;dentry-&gt;d_seq, seq))) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> -ECHILD;</span><br><span class="line"></span><br><span class="line">		<span class="comment">/*</span></span><br><span class="line"><span class="comment">		 * This sequence count validates that the parent had no</span></span><br><span class="line"><span class="comment">		 * changes while we did the lookup of the dentry above.</span></span><br><span class="line"><span class="comment">		 *</span></span><br><span class="line"><span class="comment">		 * The memory barrier in read_seqcount_begin of child is</span></span><br><span class="line"><span class="comment">		 *  enough, we can use __read_seqcount_retry here.</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">		<span class="keyword">if</span> (unlikely(__read_seqcount_retry(&amp;parent-&gt;d_seq, nd-&gt;seq))) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> -ECHILD;</span><br><span class="line"></span><br><span class="line">		*seqp = seq;</span><br><span class="line">		status = d_revalidate(dentry, nd-&gt;flags);</span><br><span class="line">		<span class="keyword">if</span> (likely(status &gt; <span class="number">0</span>)) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">			<span class="comment">/*</span></span><br><span class="line"><span class="comment">			 * Note: do negative dentry check after revalidation in</span></span><br><span class="line"><span class="comment">			 * case that drops it.</span></span><br><span class="line"><span class="comment">			 */</span></span><br><span class="line">			<span class="keyword">if</span> (unlikely(negative)) <span class="comment">// if 判断为 0</span></span><br><span class="line">				<span class="keyword">return</span> -ENOENT;</span><br><span class="line">			path-&gt;mnt = mnt;</span><br><span class="line">			path-&gt;dentry = dentry;</span><br><span class="line">			<span class="keyword">if</span> (likely(__follow_mount_rcu(nd, path, inode, seqp))) <span class="comment">// if 判断为 1</span></span><br><span class="line">				<span class="keyword">return</span> <span class="number">1</span>; <span class="comment">// 函数从这里返回</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中函数 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/dcache.c#L2103">__d_lookup_rcu()</a> 用来找到 “home” 对应的 dentry 结构体并返回其指针，具体过程此处不做分析。这里我们简单了解下 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1311">__follow_mount_rcu()</a> 函数。该函数主要用来检查路径名是否是挂载点，如果是，则找到相应挂载的文件系统，并在挂载的文件系统下继续当前的文件解析工作（而不是在旧的文件系统下继续）。这里，仍以”home”为例，该函数定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Try to skip to top of mountpoint pile in rcuwalk mode.  Fail if</span></span><br><span class="line"><span class="comment"> * we meet a managed dentry that would need blocking.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">bool</span> __follow_mount_rcu(<span class="keyword">struct</span> nameidata *nd, <span class="keyword">struct</span> path *path,</span><br><span class="line">			       <span class="keyword">struct</span> inode **inode, <span class="type">unsigned</span> *seqp)</span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">for</span> (;;) &#123;</span><br><span class="line">		<span class="class"><span class="keyword">struct</span> <span class="title">mount</span> *<span class="title">mounted</span>;</span></span><br><span class="line">		<span class="comment">/*</span></span><br><span class="line"><span class="comment">		 * Don&#x27;t forget we might have a non-mountpoint managed dentry</span></span><br><span class="line"><span class="comment">		 * that wants to block transit.</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">		<span class="keyword">switch</span> (managed_dentry_rcu(path)) &#123; <span class="comment">// 跳转至 case 0:</span></span><br><span class="line">		<span class="keyword">case</span> -ECHILD:</span><br><span class="line">		<span class="keyword">default</span>:</span><br><span class="line">			<span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">		<span class="keyword">case</span> -EISDIR:</span><br><span class="line">			<span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">		<span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (!d_mountpoint(path-&gt;dentry)) <span class="comment">// if 判断为 0(对应&#x27;home&#x27;文件夹，则为1</span></span><br><span class="line">			<span class="keyword">return</span> !(path-&gt;dentry-&gt;d_flags &amp; DCACHE_NEED_AUTOMOUNT);</span><br><span class="line"></span><br><span class="line">		mounted = __lookup_mnt(path-&gt;mnt, path-&gt;dentry);</span><br><span class="line">		<span class="keyword">if</span> (!mounted) <span class="comment">// if 判断为 1</span></span><br><span class="line">			<span class="keyword">break</span>; <span class="comment">// 结束循环</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> !read_seqretry(&amp;mount_lock, nd-&gt;m_seq) &amp;&amp;</span><br><span class="line">		!(path-&gt;dentry-&gt;d_flags &amp; DCACHE_NEED_AUTOMOUNT); <span class="comment">// return 1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namespace.c#L613">__lookup_mnt()</a> 函数与 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/dcache.c#L2103">__d_lookup_rcu()</a>  类似，只不过这里是找到挂载的文件系统，而不是 dentry。在这里，”home”文件夹确实是一个挂载点，但在我的系统里面，并没有在该目录下挂载任何文件系统，因此，  <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namespace.c#L613">__lookup_mnt()</a> 函数返回0（找不到挂载在此处的文件系统）。其实相当于这个for(;;)循环里面什么都没做，就退出了。最终该函数返回值为1。这也合理，因为”home”下没有挂载任何文件系统，不需要 <code>follow mount</code>。</p>
<p>现在回到 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数，在这里面我们还需要分析另外一个函数： <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1768">step_into()</a> 。这个函数主要是处理符号链接的情况，在这里不涉及符号链接，该函数则很简单，定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Do we need to follow links? We _really_ want to be able</span></span><br><span class="line"><span class="comment"> * to do this check without having to look at inode-&gt;i_op,</span></span><br><span class="line"><span class="comment"> * so we keep a cache of &quot;no, this doesn&#x27;t need follow_link&quot;</span></span><br><span class="line"><span class="comment"> * for the common case.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">step_into</span><span class="params">(<span class="keyword">struct</span> nameidata *nd, <span class="keyword">struct</span> path *path,</span></span><br><span class="line"><span class="params">			    <span class="type">int</span> flags, <span class="keyword">struct</span> inode *inode, <span class="type">unsigned</span> seq)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (!(flags &amp; WALK_MORE) &amp;&amp; nd-&gt;depth) <span class="comment">// if 判断为 0</span></span><br><span class="line">		put_link(nd);</span><br><span class="line">	<span class="keyword">if</span> (likely(!d_is_symlink(path-&gt;dentry)) ||</span><br><span class="line">	   !(flags &amp; WALK_FOLLOW || nd-&gt;flags &amp; LOOKUP_FOLLOW)) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="comment">/* not a symlink or should not follow */</span></span><br><span class="line">		path_to_nameidata(path, nd);</span><br><span class="line">		nd-&gt;inode = inode;</span><br><span class="line">		nd-&gt;seq = seq;</span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>; <span class="comment">// 函数由此处返回</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L834">path_to_nameidata()</a> 函数也很简单：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">path_to_nameidata</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> path *path,</span></span><br><span class="line"><span class="params">					<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (!(nd-&gt;flags &amp; LOOKUP_RCU)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		dput(nd-&gt;path.dentry);</span><br><span class="line">		<span class="keyword">if</span> (nd-&gt;path.mnt != path-&gt;mnt)</span><br><span class="line">			mntput(nd-&gt;path.mnt);</span><br><span class="line">	&#125;</span><br><span class="line">	nd-&gt;path.mnt = path-&gt;mnt;</span><br><span class="line">	nd-&gt;path.dentry = path-&gt;dentry;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>所以  <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1768">step_into()</a> 函数就相当于：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">step_into</span><span class="params">(<span class="keyword">struct</span> nameidata *nd, <span class="keyword">struct</span> path *path,</span></span><br><span class="line"><span class="params">			    <span class="type">int</span> flags, <span class="keyword">struct</span> inode *inode, <span class="type">unsigned</span> seq)</span></span><br><span class="line">&#123;</span><br><span class="line">    nd-&gt;path.mnt = path-&gt;mnt;</span><br><span class="line">    nd-&gt;path.dentry = path-&gt;dentry;</span><br><span class="line">    nd-&gt;inode = inode;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="4-3-总结"><a href="#4-3-总结" class="headerlink" title="4.3 总结"></a><font size=3>4.3 总结</font></h3><p>至此， <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数分析完毕，我们返回其调用函数 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2068">link_path_walk()</a> 。</p>
<p>我们发现<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数返回之后， <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2068">link_path_walk()</a> 函数的for(;;)循环第一次循环执行完毕，也就表示对路径的第一部分”home”的解析完毕。不难想象，在第二次执行 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2068">link_path_walk()</a> 函数的for(;;)循环时，将会解析下一个路径，也就是”sumu”。解析过程和”home”极为类似，这里不再重复分析，解析完毕之后，将解析结果同样存入 struct nameidata *nd 中，之前对”home”的解析结果则被覆盖。当第四次执行for(;;)循环时，则解析最后一部分”test.txt”。</p>
<p>对最后一部分的解析和前面的路径名解析稍有区别，不再调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数，而是直接返回到 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">path_openat()</a> 函数，将最后解析工作留给 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3257">do_last()</a> 函数来完成。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214153842041.png" alt="image-20241214153842041" />

<h2 id="5-do-last"><a href="#5-do-last" class="headerlink" title="5. do_last()"></a><font size=3>5. do_last()</font></h2><p>do_last函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3257">namei.c - fs&#x2F;namei.c - <em>do_last</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Handle the last step of open()</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">do_last</span><span class="params">(<span class="keyword">struct</span> nameidata *nd,</span></span><br><span class="line"><span class="params">		   <span class="keyword">struct</span> file *file, <span class="type">const</span> <span class="keyword">struct</span> open_flags *op)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">dir</span> =</span> nd-&gt;path.dentry;</span><br><span class="line">	<span class="type">int</span> open_flag = op-&gt;open_flag;</span><br><span class="line">	<span class="type">bool</span> will_truncate = (open_flag &amp; O_TRUNC) != <span class="number">0</span>;</span><br><span class="line">	<span class="type">bool</span> got_write = <span class="literal">false</span>;</span><br><span class="line">	<span class="type">int</span> acc_mode = op-&gt;acc_mode;</span><br><span class="line">	<span class="type">unsigned</span> seq;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">inode</span> *<span class="title">inode</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">path</span> <span class="title">path</span>;</span></span><br><span class="line">	<span class="type">int</span> error;</span><br><span class="line"></span><br><span class="line">	nd-&gt;flags &amp;= ~LOOKUP_PARENT;</span><br><span class="line">	nd-&gt;flags |= op-&gt;intent;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;last_type != LAST_NORM) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!(open_flag &amp; O_CREAT)) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="keyword">if</span> (nd-&gt;last.name[nd-&gt;last.len]) <span class="comment">// if 判断为 0</span></span><br><span class="line">			nd-&gt;flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;</span><br><span class="line">		<span class="comment">/* we _can_ be in RCU mode here */</span></span><br><span class="line">		error = lookup_fast(nd, &amp;path, &amp;inode, &amp;seq);</span><br><span class="line">		<span class="keyword">if</span> (likely(error &gt; <span class="number">0</span>)) <span class="comment">// if 判断为 1</span></span><br><span class="line">			<span class="keyword">goto</span> finish_lookup; <span class="comment">// 此处进行跳转</span></span><br><span class="line"></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">finish_lookup:</span><br><span class="line">	error = step_into(nd, &amp;path, <span class="number">0</span>, inode, seq);</span><br><span class="line">	<span class="keyword">if</span> (unlikely(error))<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">return</span> error;</span><br><span class="line">finish_open:</span><br><span class="line">	<span class="comment">/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */</span></span><br><span class="line">	error = complete_walk(nd);</span><br><span class="line">	<span class="keyword">if</span> (error) <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">return</span> error;</span><br><span class="line">	audit_inode(nd-&gt;name, nd-&gt;path.dentry, <span class="number">0</span>);</span><br><span class="line">	<span class="keyword">if</span> (open_flag &amp; O_CREAT) &#123; <span class="comment">// 这里之前看的资料链接不太一样，这里也是直接跳过</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	error = -ENOTDIR;</span><br><span class="line">	<span class="keyword">if</span> ((nd-&gt;flags &amp; LOOKUP_DIRECTORY) &amp;&amp; !d_can_lookup(nd-&gt;path.dentry))<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> out;</span><br><span class="line">	<span class="keyword">if</span> (!d_is_reg(nd-&gt;path.dentry))<span class="comment">// if 判断为 0</span></span><br><span class="line">		will_truncate = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (will_truncate) &#123;<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">finish_open_created:</span><br><span class="line">	error = may_open(&amp;nd-&gt;path, acc_mode, open_flag);</span><br><span class="line">	<span class="keyword">if</span> (error)<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> out;</span><br><span class="line">	BUG_ON(file-&gt;f_mode &amp; FMODE_OPENED); <span class="comment">/* once it&#x27;s opened, it&#x27;s opened */</span></span><br><span class="line">	error = vfs_open(&amp;nd-&gt;path, file); <span class="comment">// 这里是重点，真正执行文件打开的操作</span></span><br><span class="line">	<span class="keyword">if</span> (error)<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> out;</span><br><span class="line">opened:</span><br><span class="line">	error = ima_file_check(file, op-&gt;acc_mode);<span class="comment">// 这里 error==0</span></span><br><span class="line">	<span class="keyword">if</span> (!error &amp;&amp; will_truncate)<span class="comment">// if 判断为 0，will_truncate==0</span></span><br><span class="line">		error = handle_truncate(file);</span><br><span class="line">out:</span><br><span class="line">	<span class="keyword">if</span> (unlikely(error &gt; <span class="number">0</span>)) &#123;<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (got_write)<span class="comment">// if 判断为 0</span></span><br><span class="line">		mnt_drop_write(nd-&gt;path.mnt);</span><br><span class="line">	<span class="keyword">return</span> error;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>我们看到在do_last()函数调用complete_walk()函数之前，分别调用了lookup_fast()和step_into()函数：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214155242924.png" alt="image-20241214155242924" />

<p>相当于调用了walk_component()函数，找到文件路径最后一部分对应的dentry，并存入到 struct nameidata nd 中。</p>
<h3 id="5-1-complete-walk"><a href="#5-1-complete-walk" class="headerlink" title="5.1 complete_walk()"></a><font size=3>5.1 complete_walk()</font></h3><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L782">complete_walk()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * complete_walk - successful completion of path walk</span></span><br><span class="line"><span class="comment"> * @nd:  pointer nameidata</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If we had been in RCU mode, drop out of it and legitimize nd-&gt;path.</span></span><br><span class="line"><span class="comment"> * Revalidate the final result, unless we&#x27;d already done that during</span></span><br><span class="line"><span class="comment"> * the path walk or the filesystem doesn&#x27;t ask for it.  Return 0 on</span></span><br><span class="line"><span class="comment"> * success, -error on failure.  In case of failure caller does not</span></span><br><span class="line"><span class="comment"> * need to drop nd-&gt;path.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">complete_walk</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">dentry</span> =</span> nd-&gt;path.dentry;</span><br><span class="line">	<span class="type">int</span> status;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;flags &amp; LOOKUP_RCU) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="keyword">if</span> (!(nd-&gt;flags &amp; LOOKUP_ROOT))  <span class="comment">// if 判断为 1</span></span><br><span class="line">			nd-&gt;root.mnt = <span class="literal">NULL</span>;</span><br><span class="line">		<span class="keyword">if</span> (unlikely(unlazy_walk(nd)))  <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">return</span> -ECHILD;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (likely(!(nd-&gt;flags &amp; LOOKUP_JUMPED)))  <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>; <span class="comment">//函数返回</span></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中调用了 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L668">unlazy_walk()</a> 这个函数。该函数定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * unlazy_walk - try to switch to ref-walk mode.</span></span><br><span class="line"><span class="comment"> * @nd: nameidata pathwalk data</span></span><br><span class="line"><span class="comment"> * Returns: 0 on success, -ECHILD on failure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * unlazy_walk attempts to legitimize the current nd-&gt;path and nd-&gt;root</span></span><br><span class="line"><span class="comment"> * for ref-walk mode.</span></span><br><span class="line"><span class="comment"> * Must be called from rcu-walk context.</span></span><br><span class="line"><span class="comment"> * Nothing should touch nameidata between unlazy_walk() failure and</span></span><br><span class="line"><span class="comment"> * terminate_walk().</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">unlazy_walk</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">dentry</span> *<span class="title">parent</span> =</span> nd-&gt;path.dentry;</span><br><span class="line"></span><br><span class="line">	BUG_ON(!(nd-&gt;flags &amp; LOOKUP_RCU));</span><br><span class="line"></span><br><span class="line">	nd-&gt;flags &amp;= ~LOOKUP_RCU;</span><br><span class="line">	<span class="keyword">if</span> (unlikely(!legitimize_links(nd))) <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> out2;</span><br><span class="line">	<span class="keyword">if</span> (unlikely(!legitimize_path(nd, &amp;nd-&gt;path, nd-&gt;seq)))  <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> out1;</span><br><span class="line">	<span class="keyword">if</span> (nd-&gt;root.mnt &amp;&amp; !(nd-&gt;flags &amp; LOOKUP_ROOT)) &#123;  <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	rcu_read_unlock();</span><br><span class="line">	BUG_ON(nd-&gt;inode != parent-&gt;d_inode);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里又有两个函数需要分析：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L632">legitimize_links()</a> 和 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L615">legitimize_path()</a> 。</p>
<h4 id="5-1-1-legitimize-links"><a href="#5-1-1-legitimize-links" class="headerlink" title="5.1.1 legitimize_links()"></a><font size=3>5.1.1 legitimize_links()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L632">legitimize_links()</a> 是用来处理链接的，这里不涉及链接，因此该函数相当于空函数：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">bool</span> <span class="title function_">legitimize_links</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i;</span><br><span class="line">	<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nd-&gt;depth; i++) &#123; <span class="comment">// 这里 nd-&gt;depth = 0, 循环不执行</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="5-1-2-legitimize-path"><a href="#5-1-2-legitimize-path" class="headerlink" title="5.1.2 legitimize_path()"></a><font size=3>5.1.2 legitimize_path()</font></h4><p> <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L615">legitimize_path()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* path_put is needed afterwards regardless of success or failure */</span></span><br><span class="line"><span class="type">static</span> <span class="type">bool</span> <span class="title function_">legitimize_path</span><span class="params">(<span class="keyword">struct</span> nameidata *nd,</span></span><br><span class="line"><span class="params">			    <span class="keyword">struct</span> path *path, <span class="type">unsigned</span> seq)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> res = __legitimize_mnt(path-&gt;mnt, nd-&gt;m_seq);</span><br><span class="line">	<span class="keyword">if</span> (unlikely(res)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (unlikely(!lockref_get_not_dead(&amp;path-&gt;dentry-&gt;d_lockref))) &#123;<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> !read_seqcount_retry(&amp;path-&gt;dentry-&gt;d_seq, seq); <span class="comment">// return 1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们来看一下<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namespace.c#L568">__legitimize_mnt()</a>函数。定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* call under rcu_read_lock */</span></span><br><span class="line"><span class="type">int</span> __legitimize_mnt(<span class="keyword">struct</span> vfsmount *bastard, <span class="type">unsigned</span> seq)</span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">mount</span> *<span class="title">mnt</span>;</span></span><br><span class="line">	<span class="keyword">if</span> (read_seqretry(&amp;mount_lock, seq)) <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">	<span class="keyword">if</span> (bastard == <span class="literal">NULL</span>) <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	mnt = real_mount(bastard);</span><br><span class="line">	mnt_add_count(mnt, <span class="number">1</span>);</span><br><span class="line">	smp_mb();			<span class="comment">// see mntput_no_expire()</span></span><br><span class="line">	<span class="keyword">if</span> (likely(!read_seqretry(&amp;mount_lock, seq))) <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">0</span>; <span class="comment">// 函数返回</span></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>第 9 行：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/mount.h#L77">real_mount()</a>函数较为简单：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="keyword">struct</span> mount *<span class="title function_">real_mount</span><span class="params">(<span class="keyword">struct</span> vfsmount *mnt)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">return</span> container_of(mnt, <span class="keyword">struct</span> mount, mnt);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>是将 <a href="v4.19.71/source/include/linux/mount.h#L67">struct vfsmount</a> *mnt 转化为 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/mount.h#L34">struct mount</a> *mount (前者是后者的一个成员变量，通过宏 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kernel.h#L996">container_of()</a> 实现）。</p>
<p>第 10 行：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namespace.c#L139">mnt_add_count()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * vfsmount lock must be held for read</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">mnt_add_count</span><span class="params">(<span class="keyword">struct</span> mount *mnt, <span class="type">int</span> n)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_SMP</span></span><br><span class="line">	this_cpu_add(mnt-&gt;mnt_pcp-&gt;mnt_count, n); <span class="comment">// 略去多核cpu同步等问题，等价与 mnt-&gt;mnt_pcp-&gt;mnt_count += n</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>至此 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L615">legitimize_path()</a> 函数分析完毕，好像就做了一件事：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">container_of(nd-&gt;path-&gt;mnt)-&gt;mnt_pcp-&gt;mnt_count++; </span><br></pre></td></tr></table></figure>

<p>看起来也是关于同步问题处理相关的，就不深入分析了。</p>
<h4 id="5-1-3-总结"><a href="#5-1-3-总结" class="headerlink" title="5.1.3 总结"></a><font size=3>5.1.3 总结</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L782">complete_walk()</a> 函数中我们关心的就是 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L668">unlazy_walk()</a> 这个函数，这个函数最终其实就做了下面的事：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nd-&gt;flags &amp;= ~LOOKUP_RCU;</span><br><span class="line">container_of(nd-&gt;path-&gt;mnt)-&gt;mnt_pcp-&gt;mnt_count++;</span><br></pre></td></tr></table></figure>

<p>那么，整个<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L782">complete_walk()</a> 函数相当于:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">complete_walk</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">    nd-&gt;root.mnt = <span class="literal">NULL</span>;</span><br><span class="line">    nd-&gt;flags &amp;= ~LOOKUP_RCU;</span><br><span class="line">    container_of(nd-&gt;path-&gt;mnt,<span class="keyword">struct</span> mount, mnt)-&gt;mnt_pcp-&gt;mnt_count++;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="5-2-audit-inode"><a href="#5-2-audit-inode" class="headerlink" title="5.2 audit_inode()"></a><font size=3>5.2 audit_inode()</font></h3><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L782">complete_walk()</a> 函数执行完毕之后则进入 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/audit.h#L290">audit_inode()</a>函数，这个函数好像什么都没做，而且这个函数的定义依赖于AUDIT相关的内核配置，在某些内核配置下，这个函数的定义就是一个空函数。在这里我们不进行深入分析该函数。</p>
<h3 id="5-3-may-open"><a href="#5-3-may-open" class="headerlink" title="5.3 may_open()"></a><font size=3>5.3 may_open()</font></h3><p>下面执行 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L2946">may_open()</a> 函数，该函数主要用来检查相应打开权限，这里我们暂不分析，简单认为权限检查没有问题。</p>
<h3 id="5-4-总结"><a href="#5-4-总结" class="headerlink" title="5.4 总结"></a><font size=3>5.4 总结</font></h3><p>到这里，我们的[do_last() 函数就分析的差不多了，但是还有一个最重要的函数 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L896">vfs_open()</a> 。这个函数非常重要，可以说真正的“打开”操作是在这里进行的，前面所有的操作都是为了“找到”这个文件。后面我们重新开始一小节详细分析。</p>
<h2 id="6-vfs-open"><a href="#6-vfs-open" class="headerlink" title="6. vfs_open()"></a><font size=3>6. vfs_open()</font></h2><p>vfs_open()定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L896">open.c - fs&#x2F;open.c - <em>vfs_open</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * vfs_open - open the file at the given path</span></span><br><span class="line"><span class="comment"> * @path: path to open</span></span><br><span class="line"><span class="comment"> * @file: newly allocated file with f_flag initialized</span></span><br><span class="line"><span class="comment"> * @cred: credentials to use</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">vfs_open</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> path *path, <span class="keyword">struct</span> file *file)</span></span><br><span class="line">&#123;</span><br><span class="line">	file-&gt;f_path = *path;</span><br><span class="line">	<span class="keyword">return</span> do_dentry_open(file, d_backing_inode(path-&gt;dentry), <span class="literal">NULL</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里又调用了do_dentry_open()函数函完成文件打开的操作。</p>
<h3 id="6-1-do-dentry-open"><a href="#6-1-do-dentry-open" class="headerlink" title="6.1 do_dentry_open()"></a><font size=3>6.1 do_dentry_open()</font></h3><p>do_dentry_open()函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L735">open.c - fs&#x2F;open.c - <em>do_dentry_open</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">do_dentry_open</span><span class="params">(<span class="keyword">struct</span> file *f,</span></span><br><span class="line"><span class="params">			  <span class="keyword">struct</span> inode *inode,</span></span><br><span class="line"><span class="params">			  <span class="type">int</span> (*open)(<span class="keyword">struct</span> inode *, <span class="keyword">struct</span> file *))</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">empty_fops</span> =</span> &#123;&#125;;</span><br><span class="line">	<span class="type">int</span> error;</span><br><span class="line"></span><br><span class="line">	path_get(&amp;f-&gt;f_path);</span><br><span class="line">	f-&gt;f_inode = inode;</span><br><span class="line">	f-&gt;f_mapping = inode-&gt;i_mapping;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* Ensure that we skip any errors that predate opening of the file */</span></span><br><span class="line">	f-&gt;f_wb_err = filemap_sample_wb_err(f-&gt;f_mapping);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (unlikely(f-&gt;f_flags &amp; O_PATH)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* Any file opened for execve()/uselib() has to be a regular file. */</span></span><br><span class="line">	<span class="keyword">if</span> (unlikely(f-&gt;f_flags &amp; FMODE_EXEC &amp;&amp; !S_ISREG(inode-&gt;i_mode))) &#123;<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (f-&gt;f_mode &amp; FMODE_WRITE &amp;&amp; !special_file(inode-&gt;i_mode)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */</span></span><br><span class="line">	<span class="keyword">if</span> (S_ISREG(inode-&gt;i_mode) || S_ISDIR(inode-&gt;i_mode)) <span class="comment">// if 判断为 1</span></span><br><span class="line">		f-&gt;f_mode |= FMODE_ATOMIC_POS;</span><br><span class="line"></span><br><span class="line">	f-&gt;f_op = fops_get(inode-&gt;i_fop);</span><br><span class="line">	<span class="keyword">if</span> (unlikely(WARN_ON(!f-&gt;f_op))) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	error = security_file_open(f);</span><br><span class="line">	<span class="keyword">if</span> (error)<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> cleanup_all;</span><br><span class="line"></span><br><span class="line">	error = break_lease(locks_inode(f), f-&gt;f_flags);</span><br><span class="line">	<span class="keyword">if</span> (error)<span class="comment">// if 判断为 0</span></span><br><span class="line">		<span class="keyword">goto</span> cleanup_all;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* normally all 3 are set; -&gt;open() can clear them if needed */</span></span><br><span class="line">	f-&gt;f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;</span><br><span class="line">	<span class="keyword">if</span> (!open)     <span class="comment">// if 判断为 1</span></span><br><span class="line">		open = f-&gt;f_op-&gt;open;</span><br><span class="line">	<span class="keyword">if</span> (open) &#123;    <span class="comment">// if 判断为 1</span></span><br><span class="line">		error = open(inode, f);</span><br><span class="line">		<span class="keyword">if</span> (error) <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="keyword">goto</span> cleanup_all;</span><br><span class="line">	&#125;</span><br><span class="line">	f-&gt;f_mode |= FMODE_OPENED;</span><br><span class="line">	<span class="keyword">if</span> ((f-&gt;f_mode &amp; (FMODE_READ | FMODE_WRITE)) == FMODE_READ)</span><br><span class="line">		i_readcount_inc(inode);</span><br><span class="line">	<span class="keyword">if</span> ((f-&gt;f_mode &amp; FMODE_READ) &amp;&amp;</span><br><span class="line">	     likely(f-&gt;f_op-&gt;read || f-&gt;f_op-&gt;read_iter))</span><br><span class="line">		f-&gt;f_mode |= FMODE_CAN_READ;</span><br><span class="line">	<span class="keyword">if</span> ((f-&gt;f_mode &amp; FMODE_WRITE) &amp;&amp;</span><br><span class="line">	     likely(f-&gt;f_op-&gt;write || f-&gt;f_op-&gt;write_iter))</span><br><span class="line">		f-&gt;f_mode |= FMODE_CAN_WRITE;</span><br><span class="line"></span><br><span class="line">	f-&gt;f_write_hint = WRITE_LIFE_NOT_SET;</span><br><span class="line">	f-&gt;f_flags &amp;= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);</span><br><span class="line"></span><br><span class="line">	file_ra_state_init(&amp;f-&gt;f_ra, f-&gt;f_mapping-&gt;host-&gt;i_mapping);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* NB: we&#x27;re sure to have correct a_ops only after f_op-&gt;open */</span></span><br><span class="line">	<span class="keyword">if</span> (f-&gt;f_flags &amp; O_DIRECT) &#123;</span><br><span class="line">		<span class="keyword">if</span> (!f-&gt;f_mapping-&gt;a_ops || !f-&gt;f_mapping-&gt;a_ops-&gt;direct_IO)</span><br><span class="line">			<span class="keyword">return</span> -EINVAL;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//......</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>do_dentry_open()函数大部分在为进程生成的struct file进行赋值，填充了struct file *file 的各个成员变量，并调用驱动程序中的 “open”函数。</p>
<p>我们要关注下第 32 行：这一行是对于struct file的f_op进行赋值，该f_op的赋值会导致最终访问该文件时进行的write()、read()的行为，这个是重中之重。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">f-&gt;f_op = fops_get(inode-&gt;i_fop);</span><br></pre></td></tr></table></figure>

<p>struct file中的f_op的是直接赋值为inode&rarr;i_fop，从从这里可以看出，驱动程序的”open()”函数其实是保存在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/fs.h#L593">struct inode</a> *inode 里面的，而inode又是保存在struct dentry 里面的。通过读取相应的地址信息，并到“&#x2F;proc&#x2F;kallsys”里面进行查找，发现在上面demo中调用的驱动程序的“open”函数是“<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/ext4/file.c#L443">ext4_file_open()</a>”。<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/ext4/file.c#L443">ext4_file_open()</a> 函数这里我们不再进行深入分析了。</p>
<h2 id="7-各个函数返回"><a href="#7-各个函数返回" class="headerlink" title="7. 各个函数返回"></a><font size=3>7. 各个函数返回</font></h2><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L735">do_dentry_open()</a> 函数在这里不再进行深入分析其中的每个函数调用。do_last()函数返回之后，回到 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">path_openat()</a> 函数，由于 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3257">do_last()</a> 函数返回值为0，因此在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">path_openat()</a> 函数中退出while()循环，进入到下一条语句：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L593">terminate_walk()</a> 。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214214800378.png" alt="image-20241214214800378" />

<p>该函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">terminate_walk</span><span class="params">(<span class="keyword">struct</span> nameidata *nd)</span></span><br><span class="line">&#123;</span><br><span class="line">	drop_links(nd);</span><br><span class="line">	<span class="keyword">if</span> (!(nd-&gt;flags &amp; LOOKUP_RCU)) &#123; <span class="comment">// if 判断为 1</span></span><br><span class="line">		<span class="type">int</span> i;</span><br><span class="line">		path_put(&amp;nd-&gt;path);</span><br><span class="line">		<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nd-&gt;depth; i++)<span class="comment">// nd-&gt;depth == 0, 空循环</span></span><br><span class="line">			<span class="comment">//......</span></span><br><span class="line">		<span class="keyword">if</span> (nd-&gt;root.mnt &amp;&amp; !(nd-&gt;flags &amp; LOOKUP_ROOT)) &#123; <span class="comment">// if 判断为 0</span></span><br><span class="line">			<span class="comment">//......</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">	&#125;</span><br><span class="line">	nd-&gt;depth = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在这个函数中，由于 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L583">drop_links()</a> 是处理链接的情况，这个demo中不涉及，该函数为空函数。其中，<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L476">path_put()</a> 是进程同步相关操作，这里不进行分析。而 nd&rarr;depth 本来就等于零，因此这里 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L593">terminate_walk()</a> 除了进程同步操作之外，没有做其他工作。</p>
<p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L593">terminate_walk()</a> 函数结束之后，整个 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">path_openat()</a> 函数也就返回了，回到 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3556">do_filp_open()</a> 函数。<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3556">do_filp_open()</a>函数在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L3517">path_openat()</a> 函数执行完毕之后也就返回了。</p>
<p>现在回到最顶层函数：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L1073">do_sys_open()</a> 函数。下面将执行 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/fsnotify.h#L210">fsnotify_open()</a> 和 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/file.c#L611">fd_install()</a> 函数。 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/fsnotify.h#L210">fsnotify_open()</a> 函数在这里暂不详细分析，以后再说。</p>
<p>至此，整个<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/open.c#L1073">do_sys_open()</a> 函数分析完毕。这里只以最简单的实例进行了初步分析，并发性问题的同步控制和权限检查以及错误处理都没有考虑。后面将会再详细分析 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/fs/namei.c#L1789">walk_component()</a> 函数。</p>
<h2 id="8-总结"><a href="#8-总结" class="headerlink" title="8. 总结"></a><font size=3>8. 总结</font></h2><p>上面分析了那么多，涉及到大量的函数，大概了解一下就行，这里汇总一下函数调用关系：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-05-03-02-open%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%901/img/image-20241214223720583.png" alt="image-20241214223720583" />



<blockquote>
<p>参考资料</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/assiduous_me/article/details/124899439">Linux中open命令实现原理以及源码分析_linux open-CSDN博客</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/arm7star/article/details/78668951">linux文件描述符分配实现详解(基于ARM处理器)_fdtable-CSDN博客</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/bgao86/article/details/79346389">Linux 系统调用之open(一）_linux 系统调用之open(一)-CSDN博客</a></p>
</blockquote>

    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/9cc69d79.html">LV05-03-Kernel-05-03-02-open函数解析1</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2024年12月17日 - 23:25</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/9cc69d79.html" title="LV05-03-Kernel-05-03-02-open函数解析1">https://sumumm.github.io/post/9cc69d79.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/" rel="tag"><i class="fa fa-tag"></i> LV05-系统镜像</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/d22d4c9b.html" rel="prev" title="LV05-03-Kernel-05-03-03-open函数解析2">
                  <i class="fa fa-angle-left"></i> LV05-03-Kernel-05-03-03-open函数解析2
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/5a460a0.html" rel="next" title="LV05-03-Kernel-05-03-01-open函数简介">
                  LV05-03-Kernel-05-03-01-open函数简介 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
